#include <CesiumUtility/JsonValue.h>

#include <glm/vec3.hpp>

#include <optional>

namespace CesiumGltfContent {

/**
 * @brief Metadata obtained from a glTF that describes the skirts present on the
 * mesh.
 *
 * @remarks Skirts are a technique for hiding cracks between adjacent tiles
 * where the geometry at the edges of tiles is extended downwards, like the
 * edges of a tablecloth hanging off of a table. These skirts are included in
 * the glTF when they're generated, in the case of 3D Tiles, or they are
 * generated by Cesium Native when terrain is loaded, in the case of Quantized
 * Mesh terrain. `SkirtMeshMetadata` is attached to the glTF to allow Cesium
 * Native to know which parts of the mesh are original and which contain the
 * generated skirts, for operations such as creating texture coordinates for
 * raster overlays.
 */
struct SkirtMeshMetadata {
  /**
   * @brief Creates a new `SkirtMeshMetadata` with zeroes in all fields.
   */
  SkirtMeshMetadata() noexcept
      : noSkirtIndicesBegin{0},
        noSkirtIndicesCount{0},
        noSkirtVerticesBegin{0},
        noSkirtVerticesCount{0},
        meshCenter{0.0, 0.0, 0.0},
        skirtWestHeight{0.0},
        skirtSouthHeight{0.0},
        skirtEastHeight{0.0},
        skirtNorthHeight{0.0} {}

  /**
   * @brief Parses `SkirtMeshMetadata` from the `extras` field of a glTF mesh,
   * if present.
   *
   * @param extras The extras field of the glTF mesh.
   * @returns An optional containing the `SkirtMeshMetadata` if it was present
   * on the mesh.
   */
  static std::optional<SkirtMeshMetadata>
  parseFromGltfExtras(const CesiumUtility::JsonValue::Object& extras);

  /**
   * @brief Creates a glTF mesh extras value from the provided
   * `SkirtMeshMetadata`.
   *
   * This might be used when generating a glTF at runtime, in order to provide
   * information on the mesh's skirts to the rest of Cesium Native.
   *
   * @param skirt The skirt to create the glTF extras object from.
   * @returns An object representing the value of a glTF extras field containing
   * the skirt metadata.
   */
  static CesiumUtility::JsonValue::Object
  createGltfExtras(const SkirtMeshMetadata& skirt);

  /**
   * @brief The start index of the range of a glTF mesh's indices buffer that
   * should \b NOT be considered part of the skirt.
   */
  uint32_t noSkirtIndicesBegin;
  /**
   * @brief The length of the range of a glTF mesh's indices buffer that should
   * \b NOT be considered part of the skirt.
   *
   * Any indices outside of the range `(noSkirtIndicesBegin,
   * noSkirtIndicesBegin + noSkirtIndicesCount)` will be considered part of the
   * skirt.
   */
  uint32_t noSkirtIndicesCount;
  /**
   * @brief The start index of the range of a glTF mesh's vertices buffer that
   * should \b NOT be considered part of the skirt.
   */
  uint32_t noSkirtVerticesBegin;
  /**
   * @brief The length of the range of a glTF mesh's vertices buffer that should
   * \b NOT be considered part of the skirt.
   *
   * Any vertices outside of the range `(noSkirtVerticesBegin,
   * noSkirtVerticesBegin + noSkirtVerticesCount)` will be considered part of
   * the skirt.
   */
  uint32_t noSkirtVerticesCount;
  /**
   * @brief The center coordinates of the mesh, in \ref
   * what-are-ecef-coordinates.
   */
  glm::dvec3 meshCenter;
  /**
   * @brief The height of the skirt on the western edge of the mesh.
   */
  double skirtWestHeight;
  /**
   * @brief The height of the skirt on the southern edge of the mesh.
   */
  double skirtSouthHeight;
  /**
   * @brief The height of the skirt on the eastern edge of the mesh.
   */
  double skirtEastHeight;
  /**
   * @brief The height of the skirt on the northern edge of the mesh.
   */
  double skirtNorthHeight;
};
} // namespace CesiumGltfContent
